package com.atguigu.gmall.gateway.filter;

import com.alibaba.fastjson.JSONObject;
import com.atguigu.gmall.common.result.Result;
import com.atguigu.gmall.common.result.ResultCodeEnum;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpCookie;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.List;

/**
 * @Author: 李旭
 * @Time: 9:28
 * @Description:
 *  自定义的全局 过滤器
 */
@Component
public class LoginGlobalFilter implements GlobalFilter, Ordered {
    //GatewayFilterChain : 过滤器链     默认9大过滤器 + 自定义的过滤器

    //路径匹配实现类
    private AntPathMatcher antPathMatcher = new AntPathMatcher();
    //获取配置文件中的URLS
    @Value("${auth.url}")
    private String[] authUrl;

    @Autowired
    private RedisTemplate redisTemplate;

    //令牌
    public static final String TOKEN = "token";
    public static final String USERTEMPID = "userTempId";
    public static final String ORIGINURL = "http://passport.gmall.com/login.html?originUrl=";
    public static final String USER_LOGIN_KEY_PREFIX = "user:login:";

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        ServerHttpResponse response = exchange.getResponse();
        //获取当前请求路径
        String path = request.getURI().getPath();
        //   System.out.println("1:是路径吗？" + request.getPath().toString());
        System.out.println("2:是路径吗？" + path);
        System.out.println("3:URL：" + request.getURI().getSchemeSpecificPart());
/*        System.out.println("3:是路径吗？" + request.getRemoteAddress().getAddress().getHostName());
        System.out.println("4:是路径吗？" + request.getRemoteAddress().getHostString());*/

        //0:判断请求路径是否为内部资源  如果是内部资源就不能访问
        if(antPathMatcher.match("/**/inner/**", path)){
            //内部资源就不能访问
            //返回错误信息提示  JSON格式
            return out(response,ResultCodeEnum.PERMISSION);
        }

        //获取用户ID
        String userId = getUserId(request);

        //1:判断当前请求路径 是否需要登录   同步 + 异步
        //1.1 路径 Ajax异步请求 /api/product/auth/..
        if(antPathMatcher.match("/**/auth/**", path)
             && StringUtils.isEmpty(userId)){
            //没有登录、返回错误信息提示  JSON格式
            return out(response,ResultCodeEnum.LOGIN_AUTH);
        }
        //1.2 路径 转发页面 同步请求    trade.html pay.html ....
        for (String url : authUrl) {
            //   trade.html    path=/trade.html
            //if(path.contains(url)){
            if(path.indexOf(url) != -1 && StringUtils.isEmpty(userId)){
                //有  但没有登录  重定向
                try {
                    //重定向的地址设置在了响应头中
                    response.getHeaders().set(HttpHeaders.LOCATION,
                            ORIGINURL + URLEncoder.encode(request.getURI().getSchemeSpecificPart(),"utf-8"));
                    //设置响应头中的状态码
                    response.setStatusCode(HttpStatus.SEE_OTHER);
                } catch (UnsupportedEncodingException e) {
                    e.printStackTrace();
                }
                return response.setComplete();
            }
        }
        //3:传递用户ID
        if(!StringUtils.isEmpty(userId)){
            //使用请求头传递  userId
            request.mutate().header("userId",userId);
        }
        //4:传递临时用户ID
        String userTempId = getUserTempId(request);
        if(!StringUtils.isEmpty(userTempId)){
            request.mutate().header("userTempId",userTempId);
        }
        //放行
        return chain.filter(exchange);
    }
    //获取临时用户ID
    private String getUserTempId(ServerHttpRequest request) {
        //获取请求头 如果头有 直接使用  异步请求
        String userTempId = request.getHeaders().getFirst(USERTEMPID);
        if(StringUtils.isEmpty(userTempId)){
            //1.2:获取Cookie中    同步请求
            HttpCookie httpCookie = request.getCookies().getFirst(USERTEMPID);
            if(null != httpCookie){
                userTempId = httpCookie.getValue();
            }
        }
        return userTempId;

    }

    //获取用户ID
    private String getUserId(ServerHttpRequest request) {
        //1:获取令牌
        //1.1:获取请求头 如果头有 直接使用  异步请求
        //token:37c9bd10-3178-4401-a10e-03c4106e6e15;sadfsafdsa
        String token = request.getHeaders().getFirst(TOKEN);
        if(StringUtils.isEmpty(token)){
            //1.2:获取Cookie中    同步请求
            HttpCookie httpCookie = request.getCookies().getFirst(TOKEN);
            if(null != httpCookie){
                token = httpCookie.getValue();
            }
        }
        //判断是否获取到了令牌
        if(!StringUtils.isEmpty(token)){
            //2:连接Redis获取用户信息（用户ID）
            if(redisTemplate.hasKey(USER_LOGIN_KEY_PREFIX + token)){
                return (String) redisTemplate.opsForValue().get(USER_LOGIN_KEY_PREFIX + token);
            }
        }
        return null;
    }

    private Mono<Void> out(ServerHttpResponse response,ResultCodeEnum resultCodeEnum) {
        Result<Object> result = Result.build(null, resultCodeEnum);
        String json = JSONObject.toJSONString(result);
        DataBufferFactory dataBufferFactory = response.bufferFactory();
        //生产 DataBuffer
        DataBuffer dataBuffer = dataBufferFactory.wrap(json.getBytes());
        //设置响应response的编码为utf-8
        //HttpHeader
        //MediaType
        response.getHeaders().set(HttpHeaders.CONTENT_TYPE,
                MediaType.APPLICATION_JSON_UTF8_VALUE);
        return response.writeWith(Mono.just(dataBuffer));
    }


    //  自带9大全局过滤器 +  自定义一个 == 10大过滤器
    //10大过滤器 的执行顺序   由小大到  越小越优先执行
    // 最小（-整数最小值）<  0 <  整数最大值
    @Override
    public int getOrder() {
        return 0;
    }
}
